using System;
using System.Collections.Generic;
using HCore.Core;
using HCore.Unity.Core;
using UnityEngine;

namespace HCore.Tests.Runtime.Tilemap
{
    public class TilemapVisual : MonoBehaviour
    {
        [SerializeField] private TilemapSpriteUV[] tilemapSpriteUVArray;
        private bool IsUpdateMesh;
        private Grid2D<TilemapGridObject> mGrid;
        private Mesh mMesh;
        private Dictionary<TilemapSprite, UVCoords> mUVCoordsDictionary;

        private void Awake()
        {
            mMesh = new Mesh();
            GetComponent<MeshFilter>().mesh = mMesh;
            mUVCoordsDictionary = new Dictionary<TilemapSprite, UVCoords>();

            // 获取材质的宽高
            var texture = GetComponent<MeshRenderer>().material.mainTexture;
            float textureWidth = texture.width;
            float textureHeight = texture.height;

            // 初始化UV字典数据
            foreach (var tilemapSpriteUV in tilemapSpriteUVArray)
            {
                var uv00Pixels = tilemapSpriteUV.uv00Pixels;
                var uv11Pixels = tilemapSpriteUV.uv11Pixels;
                mUVCoordsDictionary[tilemapSpriteUV.tilemapSprite] = new UVCoords
                {
                    // 因为UV 是 0~1 的直，所以这里根据材质的宽高按计算得出 UV 值
                    UV00 = new Vector2(uv00Pixels.x / textureWidth, uv00Pixels.y / textureHeight),
                    UV11 = new Vector2(uv11Pixels.x / textureWidth, uv11Pixels.y / textureHeight)
                };
            }
        }

        private void LateUpdate()
        {
            if (IsUpdateMesh)
            {
                IsUpdateMesh = false;
                UpdateTilemapVisual();
            }
        }

        public void SetupGrid(Tilemap tilemap, Grid2D<TilemapGridObject> grid)
        {
            mGrid = grid;
            UpdateTilemapVisual();

            mGrid.AddCellChangedListener(_ => IsUpdateMesh = true);
            tilemap.AddGridObjectLoadListener(UpdateTilemapVisual);
        }

        private void UpdateTilemapVisual()
        {
            // 创建空数据的栅格
            GameUtils.CreateEmptyQuadMeshArrays(
                mGrid.Width * mGrid.Height,
                out var vertices,
                out var uv,
                out var triangles
            );

            // 循环栅格填充数据
            ForUtils.For(mGrid.Width, mGrid.Height, (x, y) =>
            {
                // 当前各自的索引
                var index = x * mGrid.Height + y;
                var quadSize = Vector2.one * mGrid.CellSize;
                var gridObject = mGrid.GetCell(x, y);
                var tilemapSprite = gridObject.GetTilemapSprite();

                Vector2 gridUV00, gridUV11;
                if (tilemapSprite == TilemapSprite.None)
                {
                    gridUV00 = Vector2.zero;
                    gridUV11 = Vector2.zero;
                    // 这里节约性能，可以完全不进行任何的绘制
                    quadSize = Vector2.zero;
                }
                else
                {
                    var uvCoords = mUVCoordsDictionary[tilemapSprite];
                    gridUV00 = uvCoords.UV00;
                    gridUV11 = uvCoords.UV11;
                }

                GameUtils.AddToMeshArrays(vertices, uv, triangles, index, mGrid.GetCellWorldPosition(x, y) + quadSize * 0.5f, 0f, quadSize, gridUV00, gridUV11);
            });

            mMesh.vertices = vertices;
            mMesh.uv = uv;
            mMesh.triangles = triangles;
        }

        private struct UVCoords
        {
            public Vector2 UV00;
            public Vector2 UV11;
        }

        [Serializable]
        public struct TilemapSpriteUV
        {
            /// <summary>
            ///     纹理精灵类型
            /// </summary>
            public TilemapSprite tilemapSprite;

            /// <summary>
            ///     纹理中 UV 起点坐标
            /// </summary>
            public Vector2Int uv00Pixels;

            /// <summary>
            ///     纹理中 UV 终点坐标
            /// </summary>
            public Vector2Int uv11Pixels;
        }
    }
}